<script setup lang="ts">
import { ref, defineModel, computed, watch } from "vue"
import * as types from "../types"
import { kindStr } from "../enums"
const oriData = defineModel<types.model>()
const data = ref<types.modelItem[]>([])
const props = defineProps({
    readonly: {
        type: Boolean,
        default: false
    }
})
let isUpdate = false
watch(oriData, () => {
    if (isUpdate) {
        isUpdate = false
        return
    }
    data.value.length = 0
    const model = oriData.value
    for (const key in model) {
        if (key.startsWith('_')) continue
        if (typeof model[key] == 'object') {
            if ('array' in model[key]) {
                data.value.push({
                    name: key,
                    kind: 'array',
                    nullable: false,
                    child: model[key].array
                })
            }
        } else {
            let arr = model[key].split(' ')
            let kind = arr[0]
            const nullable = arr[0].endsWith('?')
            if (nullable) {
                kind = kind.substring(0, kind.length - 1)
            }
            let child: string | undefined
            if (kind.startsWith('$')) {
                child = kind
                kind = 'object'
            }
            const val: types.modelItem = {
                name: key,
                kind: kind as `${kindStr}`,
                nullable,
                child
            }
            let oriKey: keyof types.modelItem = 'desc'
            for (let index = 1; index < arr.length; index++) {
                let arr2 = arr[index].split('=')
                switch (arr2[0]) {
                    case '-d':
                        val.desc = arr2[1]
                        oriKey = 'desc'
                        break;
                    case '-f':
                        val.format = arr2[1]
                        oriKey = 'format'
                        break;
                    case '-e':
                        val.enum = arr2[1]
                        oriKey = 'enum'
                        break;
                    case '-l':
                        val.length = arr2[1]
                        oriKey = 'length'
                        break;
                    case '-r':
                        val.range = arr2[1]
                        oriKey = 'range'
                        break;
                    default:
                        val[oriKey] += ' ' + arr2[0]
                        break;
                }
            }
            data.value.push(val)
        }
    }
}, { immediate: true, deep: 1 })
function dealStr(data: string) {
    if (data.startsWith('"') && data.endsWith('"')) {
        return data
    }
    if (data.indexOf(' ') >= 0 || data.indexOf('"') >= 0) {
        return '"' + data.replaceAll('"', '\\"') + '"'
    }
    return data
}
function update() {
    isUpdate = true
    let res: types.model = {}
    for (const item of data.value) {
        if (item.kind == 'array') {
            res[item.name] = { array: item.child as string }
            if (item.nullable) {
                res[item.name]['array'] += '?'
            }
        } else {
            let val = (item.kind == 'object' ? item.child : item.kind) + (item.nullable ? '?' : '')
            if (item.desc) {
                val += ' -d=' + dealStr(item.desc)
            }
            if (item.format) {
                val += ' -f=' + dealStr(item.format)
            }
            if (item.enum) {
                val += ' -e=' + dealStr(item.enum)
            }
            if (item.length) {
                val += ' -l=' + dealStr(item.length)
            }
            if (item.range) {
                val += ' -r=' + dealStr(item.range)
            }
            res[item.name] = val
        }
    }
    oriData.value = res
}
defineExpose({
    update
})
</script>
<template>
    <a-input-group compact v-for="(item, index) in data" class="model-input-item">
        <a-input v-model:value.lazy.trim="item.name" :disabled="props.readonly" placeholder="字段名称" style="width: 20%" />
        <a-select v-model:value="item.kind" style="width: 20%">
            <a-select-option v-for="x in kindStr" :value="x">{{ x }}</a-select-option>
        </a-select>
        <a-checkbox v-model:checked="item.nullable" :disabled="props.readonly"
            class="model-input-checkbox">nullable</a-checkbox>
        <a-input v-if="item.kind != 'array' && item.kind != 'object'" v-model:value.lazy.trim="item.desc"
            placeholder="备注" style="width: 45%" />
        <a-input v-if="item.kind != 'array' && item.kind != 'object'" v-model:value.lazy.trim="item.format"
            placeholder="格式" style="width: 30%" />
        <a-input v-if="item.kind != 'array' && item.kind != 'object'" v-model:value.lazy.trim="item.enum"
            placeholder="枚举值" style="width: 30%" />
        <a-input v-if="item.kind == 'string'" v-model:value.trim="item.length" placeholder="string 长度 min?-max?"
            style="width: 30%" />
        <a-input v-if="item.kind == 'long' || item.kind == 'decimal' || item.kind == 'int'"
            v-model:value.trim="item.range" placeholder="数值范围" style="width: 30%" />
        <model-ref v-if="item.kind == 'object' || item.kind == 'array'" v-model="item.child" style="width: 35%" />
        <a-button v-if="!props.readonly" danger @click="data.splice(index, 1)" style="width: 10%">
            <DeleteOutlined />
        </a-button>
    </a-input-group>
    <a-button v-if="!props.readonly" type="primary"
        @click="data.push({ name: '', kind: 'string', nullable: false })">添加字段</a-button>
</template>
<style>
.model-input-item {
    margin-bottom: 10px;
    min-width: 600px;
}

.model-input-checkbox {
    width: 15%;
    height: 30px;
}

.model-input-checkbox :last-child {
    float: left;
}
</style>